/*
 * Copyright (C) 2009 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package ferus_tigris.livewallpapers.earth;

import java.util.Random;
import java.util.Timer;
import java.util.TimerTask;

import ferus_tigris.livewallpapers.R;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.os.Handler;
import android.service.wallpaper.WallpaperService;
//import android.util.Log;
import android.view.MotionEvent;
import android.view.SurfaceHolder;

/*
 * This animated wallpaper draws a rotating wireframe cube.
 */
public class EarthWallpaper extends WallpaperService {

	private final Handler mHandler = new Handler();

	@Override
	public void onCreate() {
		super.onCreate();
	}

	@Override
	public void onDestroy() {
		super.onDestroy();
	}

	@Override
	public Engine onCreateEngine() {
		return new EarthEngine();
	}

	class EarthEngine extends Engine {

		private final Paint mPaint = new Paint();
		private float mOffset;
		private float earthOffset = 0;
		private final Bitmap background = BitmapFactory.decodeResource(getResources(), R.drawable.background);
		private final Bitmap earth = BitmapFactory.decodeResource(getResources(), R.drawable.earth);
		private final Bitmap stars = BitmapFactory.decodeResource(getResources(), R.drawable.stars);
		private final Bitmap far_stars = BitmapFactory.decodeResource(getResources(), R.drawable.far_stars);
		private final Bitmap planets = BitmapFactory.decodeResource(getResources(), R.drawable.planets);
		private final Sun sun = new Sun();
		private final Runnable mDrawCube = new Runnable() {
			public void run() {
				drawFrame();
				earthOffset++;
			}
		};
		private boolean mVisible;
		EarthEngine() {
			// Create a Paint to draw the lines for our cube
			final Paint paint = mPaint;
					//paint.setColor(0xffffffff);
				paint.setColor(0x0);
					paint.setAntiAlias(true);
					paint.setStrokeWidth(2);
					paint.setStrokeCap(Paint.Cap.ROUND);
					paint.setStyle(Paint.Style.STROKE);
					//mStartTime = SystemClock.elapsedRealtime();
		}
		@Override
		public void onCreate(SurfaceHolder surfaceHolder) {
			super.onCreate(surfaceHolder);
			// By default we don't get touch events, so enable them.
			setTouchEventsEnabled(true);
		}

		@Override
		public void onDestroy() {
			super.onDestroy();
			mHandler.removeCallbacks(mDrawCube);
		}

		@Override
		public void onVisibilityChanged(boolean visible) {
			mVisible = visible;
			if (visible) {
				drawFrame();
			} else {
				mHandler.removeCallbacks(mDrawCube);
			}
		}

		@Override
		public void onSurfaceChanged(SurfaceHolder holder, int format, int width, int height) {
			super.onSurfaceChanged(holder, format, width, height);
			drawFrame();
		}

		@Override
		public void onSurfaceCreated(SurfaceHolder holder) {
			super.onSurfaceCreated(holder);
		}

		@Override
		public void onSurfaceDestroyed(SurfaceHolder holder) {
			super.onSurfaceDestroyed(holder);
			mVisible = false;
			mHandler.removeCallbacks(mDrawCube);
		}

		@Override
		public void onOffsetsChanged(float xOffset, float yOffset,
				float xStep, float yStep, int xPixels, int yPixels) {
			mOffset = xPixels;
			drawFrame();
		}

		/*
		 * Store the position of the touch event so we can use it for drawing later
		 */
		@Override
		public void onTouchEvent(MotionEvent event) {
			if (event.getAction() == MotionEvent.ACTION_MOVE) {
			} else {
			}
			drawFrame();
			super.onTouchEvent(event);
		}

		/*
		 * Draw one frame of the animation. This method gets called repeatedly
		 * by posting a delayed Runnable. You can do any drawing you want in
		 * here. This example draws a wireframe cube.
		 */
		void drawFrame() {
			final SurfaceHolder holder = getSurfaceHolder();
			Canvas c = null;
			try {
				c = holder.lockCanvas();
				if (c != null) {
					// draw something
					drawBackground(c);
				}
			} finally {
				if (c != null) holder.unlockCanvasAndPost(c);
			}
			// Reschedule the next redraw
			mHandler.removeCallbacks(mDrawCube);
			if (mVisible) {
				mHandler.postDelayed(mDrawCube, 1000 / 25);
			}
		}
		public class Jupiter {
			final private Bitmap jupiter_dark = BitmapFactory.decodeResource(getResources(), R.drawable.jupiter_dark);
			final private Bitmap jupiter_medium = BitmapFactory.decodeResource(getResources(), R.drawable.jupiter_medium);
			final private Bitmap jupiter_light = BitmapFactory.decodeResource(getResources(), R.drawable.jupiter_light);
			final private StateManager state = new StateManager();
			public Jupiter() {
				state.setState(new DarkState(state));
				// TODO Auto-generated constructor stub
			}
			public void draw(float mCenterX, float mCenterY, Canvas c) {
				state.draw(mCenterX, mCenterY, c);
			}
			private abstract class AbstractEvent {
				
			}
			private abstract class AbstractState {
				abstract void draw(float mCenterX, float mCenterY, Canvas c);
				abstract void onEvent(AbstractEvent event);
			}
			private class TimerEvent extends AbstractEvent {
				public TimerEvent() {
					
				}
			}
			private class StateManager {
				private int offset = 0; 
				private AbstractState state = new LightState(this);
				private final Timer mHandler = new Timer();
				private final TimerTask onTimer = new TimerTask() {
					public void run() {
						//offset++;
						if(offset > 512)offset = -512;
						onEvent(new TimerEvent());
					}
				};
				public StateManager() {
					mHandler.schedule(onTimer,  1000 / 3,  1000 / 3);
				}
				public void draw(float mCenterX, float mCenterY, Canvas c) {
					state.draw(mCenterX - offset, mCenterY, c);
					//onEvent(new TimerEvent());
				}
				public void setState(AbstractState newState) {
					state = newState;
				}
				public void onEvent(AbstractEvent event) {
					state.onEvent(event);
				}
			}
			private class LightState extends AbstractState {
				private int timeouts = 0;
				private StateManager stateManager;
				public LightState(StateManager manager) {
					stateManager = manager;
				}
				public void draw(float mCenterX, float mCenterY, Canvas c) {
					c.drawBitmap(jupiter_light, mCenterX, mCenterY, null);
				}
				public void onEvent(AbstractEvent event) {
					timeouts++;
					if(timeouts > 1)
						stateManager.setState(new MediumDarkState(stateManager));
						
				}
			}
			private class MediumLightState extends AbstractState {
				private StateManager stateManager;
				public MediumLightState(StateManager manager) {
					stateManager = manager;
				}
				public void draw(float mCenterX, float mCenterY, Canvas c) {
					c.drawBitmap(jupiter_medium, mCenterX, mCenterY, null);
				}
				public void onEvent(AbstractEvent event) {
					stateManager.setState(new LightState(stateManager));
				}
			}
			private class MediumDarkState extends AbstractState {
				private StateManager stateManager;
				public MediumDarkState(StateManager manager) {
					stateManager = manager;
				}
				public void draw(float mCenterX, float mCenterY, Canvas c) {
					c.drawBitmap(jupiter_medium, mCenterX, mCenterY, null);
				}
				public void onEvent(AbstractEvent event) {
					stateManager.setState(new DarkState(stateManager));
				}
			}
			private class DarkState extends AbstractState {
				private int timeouts = 0;
				private StateManager stateManager;
				public DarkState(StateManager manager) {
					stateManager = manager;
				}
				public void draw(float mCenterX, float mCenterY, Canvas c) {
					c.drawBitmap(jupiter_dark, mCenterX, mCenterY, null);
				}
				public void onEvent(AbstractEvent event) {
					timeouts++;
					if(timeouts > 1)
						stateManager.setState(new MediumLightState(stateManager));
						
				}
			}
			
		}
		public class Sun {
			private Bitmap sun_dark = BitmapFactory.decodeResource(getResources(), R.drawable.sun);
			private Bitmap sun_light = BitmapFactory.decodeResource(getResources(), R.drawable.sun_bright);
			final private StateManager state = new StateManager();
			public Sun() {
				state.setState(new DarkState(state));
				// TODO Auto-generated constructor stub
			}
			public void draw(float mCenterX, float mCenterY, Canvas c) {
				state.draw(mCenterX, mCenterY, c);
			}
			private abstract class AbstractEvent {
				
			}
			private abstract class AbstractState {
				abstract void draw(float mCenterX, float mCenterY, Canvas c);
				abstract void onEvent(AbstractEvent event);
			}
			private class TimerEvent extends AbstractEvent {
				public TimerEvent() {
					
				}
			}
			private class StateManager {
				private AbstractState state = new LightState(this);
				private final Timer mHandler = new Timer();
				private final TimerTask onTimer = new TimerTask() {
					public void run() {
						onEvent(new TimerEvent());
					}
				};
				public StateManager() {
					mHandler.schedule(onTimer,  1000 / 3,  1000 / 3);
				}
				public void draw(float mCenterX, float mCenterY, Canvas c) {
					state.draw(mCenterX, mCenterY, c);
					//onEvent(new TimerEvent());
				}
				public void setState(AbstractState newState) {
					state = newState;
				}
				public void onEvent(AbstractEvent event) {
					state.onEvent(event);
				}
			}
			private class LightState extends AbstractState {
				private int timeouts = 0;
				private StateManager stateManager;
				public LightState(StateManager manager) {
					stateManager = manager;
				}
				public void draw(float mCenterX, float mCenterY, Canvas c) {
					c.drawBitmap(sun_light, mCenterX, mCenterY, null);
				}
				public void onEvent(AbstractEvent event) {
					timeouts++;
					if(timeouts > 0)
						stateManager.setState(new DarkState(stateManager));
						
				}
			}
			private class DarkState extends AbstractState {
				private int timeouts = 0;
				private StateManager stateManager;
				public DarkState(StateManager manager) {
					stateManager = manager;
				}
				public void draw(float mCenterX, float mCenterY, Canvas c) {
					c.drawBitmap(sun_dark, mCenterX, mCenterY, null);
				}
				public void onEvent(AbstractEvent event) {
					timeouts++;
					if(timeouts > 3)
						stateManager.setState(new LightState(stateManager));
						
				}
			}
			
		}
		/*
		 * Draw a wireframe cube by drawing 12 3 dimensional lines between
		 * adjacent corners of the cube
		 */
		void drawBackground(Canvas c) {
			c.save();
			//c.translate(mCenterX, mCenterY);
			c.drawColor(0xff000000);
			float scaleX = c.getWidth()/earth.getWidth();
			float offset = mOffset;
			offset *= 0.5;
			offset -= earth.getWidth()/8;
			c.drawBitmap(earth, offset + earthOffset, 0, null);
			c.drawBitmap(earth, offset + earthOffset - earth.getWidth(), 0, null);
			if(offset + earthOffset > earth.getWidth())earthOffset = 0;
			c.drawBitmap(background, offset, 0, null);
			c.drawBitmap(stars, (int)(offset*(1.7)), 0, null);
			c.drawBitmap(far_stars, (int)(offset*(1.5)), 0, null);
			c.drawBitmap(planets, (int)(offset*(2)), 0, null);
			sun.draw(offset, 0, c);
			c.restore();
		}

	}
}
